package com.okaixz.client.service.impl;

import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.okaixz.client.mapper.OrderInfoMapper;
import com.okaixz.client.model.domain.Goods;
import com.okaixz.client.model.domain.OrderInfo;
import com.okaixz.client.model.domain.User;
import com.okaixz.client.model.dto.OrderInfoDto;
import com.okaixz.client.model.dto.UserDto;
import com.okaixz.client.model.dto.WxPayAttachInfo;
import com.okaixz.client.model.vo.WxAppPayResult;
import com.okaixz.client.service.IGoodsService;
import com.okaixz.client.service.IOrderInfoService;
import com.okaixz.client.service.IUserService;
import com.okaixz.client.wechat.WxAppPayService;
import com.okaixz.common.client.exception.BusinessException;
import com.okaixz.common.client.exception.CommonErrorCode;
import com.okaixz.common.constant.CommonConstants;
import com.okaixz.common.constant.RedisConstants;
import com.okaixz.common.core.redis.RedisCache;
import com.okaixz.manager.utils.MyIdUtil;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.BeanUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import java.time.LocalDateTime;
import java.util.List;
import java.util.concurrent.TimeUnit;
import java.util.stream.Collectors;

/**
 * <p>
 * 服务实现类
 * </p>
 *
 * @author cdz
 * @since 2024-10-17
 */
@Service
@Slf4j
public class OrderInfoServiceImpl extends ServiceImpl<OrderInfoMapper, OrderInfo> implements IOrderInfoService {

    @Autowired
    private IGoodsService goodsService;
    @Autowired
    private WxAppPayService wxAppPayService;

    @Autowired
    private RedisCache redisCache;

    @Autowired
    private MyIdUtil idUtil;

    @Autowired
    private IUserService userService;

    @Override
    public List<OrderInfoDto> getListByUserId(String userId) {
        if (userId == null) {
            return null;
        }
        List<OrderInfo> list = lambdaQuery()
                .eq(OrderInfo::getUserId, userId)
                .orderByDesc(OrderInfo::getCreateTime)
                .list();
        if (list == null) {
            return null;
        }
        //将list转为dto
        List<OrderInfoDto> dtoList = list.stream().map(orderInfo -> {
            OrderInfoDto dto = new OrderInfoDto();
            BeanUtils.copyProperties(orderInfo, dto);
            return dto;
        }).collect(Collectors.toList());
        return dtoList;
    }

    @Override
    @Transactional
    public OrderInfo createOrderAndSaveInCache(String userId, String clientName,Integer gid) {
        Goods goods = goodsService.getGoodsById(gid,clientName);
        if (goods == null) {
            throw new BusinessException(CommonErrorCode.GOODS_NOT_EXIST);
        }

        OrderInfo orderInfo = new OrderInfo();
        long nextId = idUtil.nextId(RedisConstants.ORDER_ID_ICR_KEY_PREF);
        log.info("nextId={}", nextId);
        orderInfo.setId(nextId);
        orderInfo.setUserId(userId);
        orderInfo.setCreateTime(LocalDateTime.now());
        orderInfo.setGid(gid);
        orderInfo.setGprice(goods.getPrice());
        orderInfo.setGname(goods.getName());
        orderInfo.setClientName(clientName);

        //        log.info("order={}",orderInfo);

        String orderInfoKey = getOrderInfoKey(nextId + "");
        log.info("orderInfoKey:{}", orderInfoKey);
        redisCache.setCacheObject(orderInfoKey, orderInfo, 5, TimeUnit.MINUTES);//保存订单到redis缓存 5分钟后失效

        return orderInfo;
    }

    @Override
    public OrderInfo createOrder(String userId, Integer gid) {
        Goods goods = goodsService.getGoodsById(gid,"");
        if (goods == null) {
            return null;
        }

        OrderInfo orderInfo = new OrderInfo();
        long nextId = idUtil.nextId(RedisConstants.ORDER_ID_ICR_KEY_PREF);
        log.info("nextId={}", nextId);
        orderInfo.setId(nextId);
        orderInfo.setUserId(userId);
        orderInfo.setCreateTime(LocalDateTime.now());
        orderInfo.setGid(gid);
        orderInfo.setGprice(goods.getPrice());
        orderInfo.setGname(goods.getName());


        return orderInfo;
//        return null;
    }

    @Override
    public OrderInfo getCacheOrder(String orderId) {
        String orderInfoKey = getOrderInfoKey(orderId);
        Object cacheObject = redisCache.getCacheObject(orderInfoKey);
        if (cacheObject == null) {
            return null;
        }
        OrderInfo orderInfo = (OrderInfo) cacheObject;
        return orderInfo;
    }

    @Override
    public OrderInfo getOrderFromRedisOrDb(String orderId) {
        OrderInfo orderInfo = getCacheOrder(orderId);
        if (orderInfo != null) {
            return orderInfo;
        }
        orderInfo = lambdaQuery()
                .eq(OrderInfo::getId, orderId)
                .one();
        return orderInfo;
    }

    @Override
    public UserDto queryWxAppPayOrder(String orderId) {
        WxAppPayResult wxAppPayResult = wxAppPayService.queryOrderByOutTradeNo(orderId);

        return processWxAppPayResult(wxAppPayResult);
    }

    @Override
    public UserDto processWxAppPayResult(WxAppPayResult wxAppPayResult) {
        if (wxAppPayResult == null) {
            return null;
        }
        String sessionId = null;

        int payStatus = CommonConstants.PAY_STATUS_NOTPAY;
        String transactionId = null;
        String tradeType = null;
        if (wxAppPayResult.isSuccess()) {
            //支付成功
            payStatus = CommonConstants.PAY_STATUS_PAY_SUCCESS;
            transactionId = wxAppPayResult.getTransaction_id();
            tradeType = wxAppPayResult.getTrade_type();
        } else {
            //支付失败
            payStatus = CommonConstants.PAY_STATUS_PAY_FAIL;
        }

        String outTradeNo = wxAppPayResult.getOut_trade_no();
        WxPayAttachInfo attachInfo = wxAppPayResult.getAttachInfo();
        if (attachInfo != null) {
            sessionId=attachInfo.getC();
        }


        //从缓存中取订单信息
        OrderInfo orderInfo = getOrderFromRedisOrDb(outTradeNo);

        if (orderInfo == null) {
            if (attachInfo == null) {
                // TODO: 2024/10/25 缓存中没有订单信息 附加信息又为空 将支付记录到异常表中
                return null;
            }
            //缓存中没有订单信息 重新创建一个订单信息
            String userId = attachInfo.getA();
            Integer gid = attachInfo.getB();

            orderInfo = createOrder(userId, gid);
        }
        log.info("processAppPayCallback userId={}", orderInfo.getUserId());
        log.info("gid={}", orderInfo.getGid());
        log.info("sessionId={}", sessionId);

        orderInfo.setPayType(CommonConstants.PAY_TYPE_WXPAY);
        orderInfo.setPayState(payStatus);
        orderInfo.setPayTime(wxAppPayResult.getPayTime());
        orderInfo.setTrade_type(tradeType);
        orderInfo.setTransaction_id(transactionId);


        UserDto userDto=null;
        if(payStatus==CommonConstants.PAY_STATUS_PAY_SUCCESS){
            //支付成功且没有记录到数据库的订单才能增加使用次数或会员时长
            OrderInfo one = lambdaQuery()
                    .eq(OrderInfo::getTransaction_id, transactionId)
                    .eq(OrderInfo::getPayState, payStatus)
                    .one();
            if(one == null){
                save(orderInfo);//保存订单信息到数据库中
                userDto=userService.updateVipInfo(orderInfo.getGid(), orderInfo.getUserId());//更新数据库中的vip用户信息

            }else {
                User userFromRedis = userService.getUserFromRedis(orderInfo.getUserId());
                userDto=new UserDto();
                BeanUtils.copyProperties(userFromRedis,userDto);
            }
        }
        return userDto;
    }

    private String getOrderInfoKey(String orderId) {
        StringBuilder sb = new StringBuilder();
        sb.append(RedisConstants.ORDER_INFO_CACHE_PREF);
        sb.append(orderId);
        return sb.toString();
    }


}
